/*************************************************************************
 *                                                                       *
 * This file is part of the DogosFrame distribution.  For full copyright *
 * information, see COPYRIGHT and COPYING.LESSER.                        *
 *                                                                       *
 * Author:           sqbang                                              *
 * Email:            sqbang@ustc.edu                                     *
 *                                                                       *
 *************************************************************************/

//declaration header
#include "COMMON/para/DOGOS_MPI.h"

//C++ headers
#include <iostream>
#include <stdlib.h>

#ifdef DOGOS_HAVE_MPI
DOGOS_MPI::Comm DOGOS_MPI::comm_world = MPI_COMM_NULL;
DOGOS_MPI::Comm DOGOS_MPI::comm_null  = MPI_COMM_NULL;

bool DOGOS_MPI::s_mpi_is_initialized = false;
DOGOS_MPI DOGOS_MPI::s_mpi_world (DOGOS_MPI::comm_null);
#else
DOGOS_MPI::Comm DOGOS_MPI::comm_world = 0;
DOGOS_MPI::Comm DOGOS_MPI::comm_null  = 0;

bool DOGOS_MPI::s_mpi_is_initialized = false;
DOGOS_MPI DOGOS_MPI::s_mpi_world (DOGOS_MPI::comm_null);
#endif



void
DOGOS_MPI::init (
    int& argc,
    char** argv)
{
#ifdef DOGOS_HAVE_MPI
    MPI_Init (&argc, &argv);
    s_mpi_is_initialized = true;

    MPI_Comm_dup  (MPI_COMM_WORLD,     &s_mpi_world.d_comm);
    MPI_Comm_rank (s_mpi_world.d_comm, &s_mpi_world.d_rank);
    MPI_Comm_size (s_mpi_world.d_comm, &s_mpi_world.d_size);

    comm_world = MPI_COMM_WORLD;
    comm_null  = MPI_COMM_NULL;
#else
    (void)argc;
    (void)argv;
#endif
}



void
DOGOS_MPI::init (
    Comm comm)
{
#ifdef DOGOS_HAVE_MPI
    if (comm == MPI_COMM_NULL)
    {
        std::cerr << "DOGOS_MPI::init: invalid initializing Communicator." << std::endl;
    }

    s_mpi_is_initialized = true;
    MPI_Comm_dup  (comm,               &s_mpi_world.d_comm);
    MPI_Comm_rank (s_mpi_world.d_comm, &s_mpi_world.d_rank);
    MPI_Comm_size (s_mpi_world.d_comm, &s_mpi_world.d_size);

    comm_world = MPI_COMM_WORLD;
    comm_null  = MPI_COMM_NULL;
#else
    (void)comm;
#endif
}



void
DOGOS_MPI::finalize()
{
#ifdef DOGOS_HAVE_MPI
    // check if mpi is initialized before calling Comm_free
    if (s_mpi_is_initialized)
    {
        MPI_Comm_free (&s_mpi_world.d_comm);
    }

    MPI_Finalize();
#endif
}



void
DOGOS_MPI::abort()
{
#ifdef DOGOS_HAVE_MPI
    const DOGOS_MPI& mpi(DOGOS_MPI::get_MPI_world());
    if (mpi.size() > 1)
    {
        MPI_Abort(mpi.get_communicator(), -1);
    }
    else
    {
        exit(-1);
    }
#else
    exit(-1);
#endif
}
